#pragma once

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <functional>
#include "InetAddr.hpp"
#include "Common.hpp"

static const int gsockfd = -1;
static const uint16_t gport = 8888;

using func_t = std::function<std::string(const std::string&)>;


class udpserver
{

public:
    udpserver(func_t func,int sockfd = gsockfd,uint16_t port = gport)
        : _isrunning(false),_sockfd(sockfd), _port(port),_func(func)
    {
    }

    void Initserver()
    {
        // create sockfd
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 别又int
        if (_sockfd < 0)
        {
            std::cout << "sockfd error" << std::endl;
            exit(SOCKFD_ERROR);
        }
        std::cout << "sockfd success: " << _sockfd << std::endl;

        // server imformation
        struct sockaddr_in server;
        memset(&server, 9, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_port); // htons
        server.sin_addr.s_addr = INADDR_ANY;

        // bind
        socklen_t len = sizeof(server);
        int n = ::bind(_sockfd, (struct sockaddr *)&server, len);
        if (n < 0)
        {
            std::cout << "Bind error" << std::endl;
            exit(BIND_ERROR);
        }
        std::cout << "Bind success" << std::endl;
    }

    void start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // recvfrom
            char inbuffer[1024];
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                perror("recvfrom");
                exit(RECVFORM_ERROR);
            }
            // send
            else
            {
                InetAddr addr(client);

                std::string client_info = addr.IP() + std::to_string(addr.Port());
                
                // std::string info = "[lazy_client find]#";
                printf("[%s:%s]find#", addr.IP().c_str(), std::to_string(addr.Port()).c_str());
                std::cout << inbuffer << std::endl;
                // info += inbuffer;
                // std::cout << info << std::endl;

                // 处理业务
                std::string ans = _func(inbuffer);
                
                ssize_t n = sendto(_sockfd, ans.c_str(), ans.size(), 0, (struct sockaddr*)&client, len);
                if(n < 0)
                {
                    std::cout << "sendto error" << std::endl;
                    exit(SENDTO_ERROR);
                }
            }
        }
        _isrunning = false;
    }

    ~udpserver()
    {
        if(_sockfd < 0) ::close(_sockfd);
    }

private:
    uint16_t _port;
    int _sockfd;
    func_t _func;
    /* std::string _serverip;  server端不需要ip */
    bool _isrunning;
};